package br.com.furb.trabalhoFinal.controller;

import br.com.furb.trabalhoFinal.Exceptions.LancamentoException;
import br.com.furb.trabalhoFinal.Exceptions.QuantidadeMarcacoesInvalidException;
import br.com.furb.trabalhoFinal.model.Colaborador;
import br.com.furb.trabalhoFinal.model.Folha;
import br.com.furb.trabalhoFinal.model.Lancamento;
import br.com.furb.trabalhoFinal.model.Marcacoes;
import java.util.Date;
import java.util.logging.Level;
import java.util.logging.Logger;

public class GeradorDeFolha {

  public Folha gerarFolha(Colaborador colaborador, Date referencia) {
    Lancamento inss = null;
    Lancamento ir = null;
    int lastCod = 0;
    double totalVencimentos = 0;
    double totalDescontos = 0;
    for (Lancamento lancamento : colaborador.getLancamentos()) {
      if (lancamento.getCodigo() > lastCod) {
        lastCod = lancamento.getCodigo();
      }
      if(lancamento.getDebito()){
        totalDescontos += lancamento.getValor();
      }else{
        totalVencimentos += lancamento.getValor();
      }
    }
    double valorINSS = calcularValorINSS(colaborador.getSalario());
    if (valorINSS != 0) {
      inss = new Lancamento();
      lastCod++;
      try {
        inss.setCodigo(lastCod);
        inss.setDebito(true);
        inss.setDescricao("INSS");
        inss.setValor(valorINSS);

      } catch (LancamentoException ex) {
        throw new RuntimeException(ex.getMessage());
      }
    }

    double valorIR = calcularValorIR(colaborador.getSalario());
    if (valorIR != 0) {
      ir = new Lancamento();
      lastCod++;
      try {
        ir.setCodigo(lastCod);
        ir.setDebito(true);
        ir.setDescricao("INSS");
        ir.setValor(valorIR);
      } catch (LancamentoException ex) {
        throw new RuntimeException(ex.getMessage());
      }
    }
    Folha folha = new Folha();
    try {
      folha.setHorasTrabalhadas(calcularHorasTrabalhadas(colaborador));
    } catch (QuantidadeMarcacoesInvalidException ex) {
      throw new RuntimeException(ex.getMessage());
    }
    folha.setColaborador(colaborador);
    folha.setTotalVencimentos(totalVencimentos);
    folha.setTotalDescontos(totalDescontos);
    folha.setDataGeracao(new Date());
    folha.setReferencia(referencia);
    return folha;
  }

  /**
   * Essa rotina já está com um controle de flexibilidade de 10 minutos,
   * verificar necessidade de flag para marcar / desmarcar
   *
   * HOW-TO: faz segunda marcação - primeira, pra saber tempo efetivo, depois
   * adiciona 2 no índice para que na segunda vez faz terceira marcação -
   * segunda, pra saber tempo efetivo, soma de novo, e assim por diante. pois
   * entre 2ª e 3ª marcações o colaborador não está trabalhando, logo não é
   * necessário somar esse tempo e ele pode fazer quantas pausas quiser
   *
   * @param colaborador @
   *
   * return horas trabalhadas(ex: 8.5 horas, ou 8.13 horas),etc...
   */
  public double calcularHorasTrabalhadas(Colaborador colaborador) throws QuantidadeMarcacoesInvalidException {
    double ret = 0;
    double horasDoDia;
    double cargaHoraria;
    for (Marcacoes dia : colaborador.getMarcacoes().values()) {
      int i = 0;
      if (dia.getMarcacoes().size() % 2 != 0) {
        throw new QuantidadeMarcacoesInvalidException();
      }
      while (i + 1 < dia.getMarcacoes().size()) {

        horasDoDia = dia.getMarcacoes().get(i + 1) - dia.getMarcacoes().get(i);
        cargaHoraria = colaborador.getCargo().getCargaHoraria();
        ret += (horasDoDia > (cargaHoraria - 10) && horasDoDia < (cargaHoraria + 10)) ? cargaHoraria : horasDoDia;

        i++;
        i++;
      }
    }
    return ret / 60;
  }

  private double calcularValorINSS(double salario) {
    if (salario < 1247.70) {
      return salario * 0.08;
    }
    if (salario < 2079.50) {
      return salario * 0.09;
    }
    if (salario < 4159.00) {
      return salario * 0.11;
    }
    return 0;
  }

  private double calcularValorIR(double salario) {
    if (salario < 1710.78) {
      return 0;
    }
    if (salario < 2563.91) {
      return 128.31;
    }
    if (salario < 3418.59) {
      return 320.60;
    }
    if (salario < 4271.59) {
      return 577.00;
    }
    return 790.58;
  }
}
